﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="EnumerationExtension.cs" company="Concept Architecture">
//   (c) 2010 Muhammad Umer Farooq
// </copyright>
// <summary>
//   Defines the EnumerationExtension type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Hisaab.Client.Common.Helpers
{
    using System;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows.Markup;

    /// <summary>
    /// Defines the <seealso cref="EnumerationExtension"/> type.
    /// </summary>
    public class EnumerationExtension : MarkupExtension
    {
        /// <summary>
        /// Member variable _enumType
        /// </summary>
        private Type _enumType;

        /// <summary>
        /// Initializes a new instance of the <see cref="EnumerationExtension"/> class.
        /// </summary>
        /// <param name="enumType">Type of the enum.</param>
        public EnumerationExtension(Type enumType)
        {
            if (enumType == null)
            {
                throw new ArgumentNullException("enumType");
            }

            EnumType = enumType;
        }

        /// <summary>
        /// Gets the type of the enum.
        /// </summary>
        /// <value>
        /// The type of the enum.
        /// </value>
        public Type EnumType
        {
            get
            {
                return _enumType;
            }

            private set
            {
                if (_enumType == value)
                {
                    return;
                }

                var enumType = Nullable.GetUnderlyingType(value) ?? value;

                if (enumType.IsEnum == false)
                {
                    throw new ArgumentException("Type must be an Enum.");
                }

                _enumType = value;
            }
        }

        /// <summary>
        /// When implemented in a derived class, returns an object that is set as the value of the target property for this markup extension.
        /// </summary>
        /// <param name="serviceProvider">Object that can provide services for the markup extension.</param>
        /// <returns>
        /// The object value to set on the property where the extension is applied.
        /// </returns>
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            var enumValues = Enum.GetValues(EnumType);

            return (
              from object enumValue in enumValues
              select new EnumerationMember
              {
                  Value = enumValue,
                  Description = GetDescription(enumValue)
              }).ToArray();
        }

        /// <summary>
        /// Gets the description.
        /// </summary>
        /// <param name="enumValue">The enum value.</param>
        /// <returns>Description of enum</returns>
        private string GetDescription(object enumValue)
        {
            var descriptionAttribute = EnumType
              .GetField(enumValue.ToString())
              .GetCustomAttributes(typeof(DescriptionAttribute), false)
              .FirstOrDefault() as DescriptionAttribute;

            return descriptionAttribute != null
              ? descriptionAttribute.Description
              : enumValue.ToString();
        }

        /// <summary>
        /// Defines the <seealso cref="EnumerationMember"/> type.
        /// </summary>
        public class EnumerationMember
        {
            /// <summary>
            /// Gets or sets the description.
            /// </summary>
            /// <value>
            /// The description.
            /// </value>
            public string Description { get; set; }

            /// <summary>
            /// Gets or sets the value.
            /// </summary>
            /// <value>
            /// The value.
            /// </value>
            public object Value { get; set; }
        }
    }
}